/**
 * OSAmI: Open Source Ambient Intelligence
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: osami-general@osami-commons.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */

package org.osami.gateway.sensor.internal;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.felix.ipojo.annotations.Bind;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.ServiceProperty;
import org.apache.felix.ipojo.annotations.Unbind;
import org.apache.felix.ipojo.annotations.Validate;
import org.osami.gateway.sensor.data.IUpdatableSense;
import org.osami.gateway.sensor.data.SenseNode;
import org.osami.gateway.sensor.internal.message.EventPayload;
import org.osami.gateway.sensor.protocol.ConfigurationChangeListener;
import org.osami.gateway.sensor.protocol.IPayload;
import org.osami.gateway.sensor.protocol.ISensorDevice;
import org.osgi.framework.ServiceReference;
import org.osgi.service.device.Constants;

/**
 * Created by IntelliJ IDEA.
 * User: guillaume
 * Date: 16 juin 2010
 * Time: 12:53:46
 * To change this template use File | Settings | File Templates.
 */
@Component
@Provides
public class SensorDevice implements ISensorDevice {
    private static final Logger logger = Logger.getLogger(SensorDevice.class.getName());

    public final static int MATCH_SERIAL = 10;
    public final static int MATCH_TYPE = 5;

    public final static String TEMPERATURE_KEY = "Temp";
    public final static String HUMIDITY_KEY = "Hydro";
    public final static String LIGHT_KEY = "Light";

    private Map<ServiceReference, IUpdatableSense> senses;

    @ServiceProperty(name = Constants.DEVICE_CATEGORY,
                     value = "{OSAmIFRSensor}")
    private String[] categories;

    @ServiceProperty(name = Constants.DEVICE_SERIAL,
                     mandatory = true)
    private String serial;

    @ServiceProperty(name = "device.type",
                     value = "osamifrsensor")
    private String type;

    @ServiceProperty(value = SenseNode.TOPIC_PREFIX + "sensor")
    private String topic;

    @ServiceProperty(name = "device.metadata")
    private Map<String, String> metadata;

    private ConfigurationChangeListener listener;

    public SensorDevice() {
        senses = new HashMap<ServiceReference, IUpdatableSense>();
    }

    @Validate
    private void start()
    {
        logger.info("SensorDevice " + this + " is starting");
    }

    @Invalidate
    private void stop()
    {
        logger.info("SensorDevice " + this + " is stopping");
    }

    @Bind(id= "senses", filter = "(device.id=<to-be-set-dynamically>)", aggregate = true, optional = true)
    public void bindSense(IUpdatableSense sense, ServiceReference reference) {
        logger.info("SensorDevice: bindSense" + reference);
        synchronized (senses) {
            senses.put(reference, sense);
        }
    }

    @Unbind(id= "senses", filter = "(device.id=<to-be-set-dynamically>)", aggregate = true, optional = true)
    public void unbindSense(ServiceReference reference) {
        logger.info("SensorDevice: unbindSense" + reference);
        IUpdatableSense sense = senses.get(reference);
        if (sense != null) {
            synchronized (senses) {
                senses.remove(reference);
            }
        }
    }

    public void noDriverFound() {
        logger.info("SensorDevice.noDriverFound()");
    }

    public void dispatch(IPayload payload) {
        // We will only handle event type message
        if (IPayload.Type.EVENT.equals(payload.getType())) {
            EventPayload event = (EventPayload) payload;

            for (IUpdatableSense sense : senses.values()) {
                String senseId = sense.getSenseId();
                String value;
                value = event.get(senseId);
                if (value != null) {
                    logger.fine("Event contains data for " + senseId);
                    sense.update(Integer.parseInt(value));
                }
            }
        }
    }

    public void registerConfigurationChangeListener(ConfigurationChangeListener listener) {
        logger.info("SensorDriver.registerConfigurationChangeListener(" + listener + ")");
        this.listener = listener;
    }

    public void notifyConfigurationChange() {
        logger.info("SensorDriver.notifyConfigurationChange()");
        if (listener != null) {
            listener.configurationChanged(serial);
        }
    }
}
